home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / mipsABI / examples / sup / PORT / step06 / scan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  22.2 KB  |  980 lines

  1. /*
  2.  * Copyright (c) 1992 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  12.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  13.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  14.  *
  15.  * Carnegie Mellon requests users of this software to return to
  16.  *
  17.  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
  18.  *  School of Computer Science
  19.  *  Carnegie Mellon University
  20.  *  Pittsburgh PA 15213-3890
  21.  *
  22.  * any improvements or extensions that they make and grant Carnegie Mellon
  23.  * the rights to redistribute these changes.
  24.  */
  25. /*
  26.  * scan.c - sup list file scanner
  27.  *
  28.  **********************************************************************
  29.  * HISTORY
  30.  * $Log: scan.c,v $
  31.  * Revision 1.1.1.1  1993/05/21  14:52:17  cgd
  32.  * initial import of CMU's SUP to NetBSD
  33.  *
  34.  * Revision 1.8  92/08/11  12:04:28  mrt
  35.  *     Brad's changes: delinted, added forward declarations of static
  36.  *     functions.Added Copyright.
  37.  *     [92/07/24            mrt]
  38.  * 
  39.  * 18-Mar-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  40.  *    Added host=<hostfile> support to releases file.
  41.  *
  42.  * 11-Mar-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
  43.  *    Added "rsymlink" recursive symbolic link quoting directive.
  44.  *
  45.  * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  46.  *    Added code for "release" support.
  47.  *
  48.  * 26-May-87  Doug Philips (dwp) at Carnegie-Mellon University
  49.  *    Lets see if we'll be able to write the scan file BEFORE
  50.  *    we collect the data for it.  Include sys/file.h and use
  51.  *    new definitions for access check codes.
  52.  *
  53.  * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  54.  *    Added type casting information for lint.
  55.  *
  56.  * 21-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  57.  *    Added check for newonly upgrade when lasttime is the same as
  58.  *    scantime.  This will save us the trouble of parsing the scanfile
  59.  *    when the client has successfully received everything in the
  60.  *    scanfile already.
  61.  *
  62.  * 16-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  63.  *    Clear Texec pointers in execT so that Tfree of execT will not
  64.  *    free command trees associated with files in listT.
  65.  *
  66.  * 06-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  67.  *    Added code to omit scanned files from list if we want new files
  68.  *    only and they are old.
  69.  *
  70.  * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  71.  *    Major rewrite for protocol version 4.  Added version numbers to
  72.  *    scan file.  Also added mode of file in addition to flags.
  73.  *    Execute commands are now immediately after file information.
  74.  *
  75.  * 13-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  76.  *    Added comments to list file format.
  77.  *
  78.  * 08-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  79.  *    Added code to implement omitany.  Currently doesn't know about
  80.  *    {a,b,c} patterns.
  81.  *
  82.  * 07-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  83.  *    Created.
  84.  *
  85.  **********************************************************************
  86.  */
  87.  
  88. #include <libc.h>
  89. #include <c.h>
  90. #include <sys/types.h>
  91. #include <sys/time.h>
  92. #include <sys/stat.h>
  93. #include <sys/dir.h>
  94. #include <sys/file.h>
  95. #ifdef _ABI_SOURCE
  96. #include <utime.h>
  97. #endif
  98. #include "sup.h"
  99.  
  100. /*************************
  101.  ***    M A C R O S    ***
  102.  *************************/
  103.  
  104. #define SPECNUMBER 1000
  105.     /* number of filenames produced by a single spec in the list file */
  106.  
  107. /*******************************************
  108.  ***    D A T A   S T R U C T U R E S    ***
  109.  *******************************************/
  110.  
  111. typedef enum {            /* release options */
  112.     ONEXT,        OPREFIX,    OLIST,        OSCAN,
  113.     OHOST
  114. } OPTION;
  115.  
  116. static char *options[] = {
  117.     "next",        "prefix",    "list",        "scan",
  118.     "host",
  119.     0
  120. };
  121.  
  122. typedef enum {            /* <collection>/list file lines */
  123.     LUPGRADE,    LOMIT,        LBACKUP,    LEXECUTE,
  124.     LINCLUDE,    LNOACCT,    LOMITANY,    LALWAYS,
  125.     LSYMLINK,    LRSYMLINK
  126. } LISTTYPE;
  127.  
  128. static char *ltname[] = {
  129.     "upgrade",    "omit",        "backup",    "execute",
  130.     "include",    "noaccount",    "omitany",    "always",
  131.     "symlink",    "rsymlink",
  132.     0
  133. };
  134.  
  135. #define FALWAYS        FUPDATE
  136.  
  137. /* list file lines */
  138. static TREE *upgT;            /* files to upgrade */
  139. static TREE *flagsT;            /* special flags: BACKUP NOACCT */
  140. static TREE *omitT;            /* recursize file omition list */
  141. static TREE *omanyT;            /* non-recursize file omition list */
  142. static TREE *symT;            /* symbolic links to quote */
  143. static TREE *rsymT;            /* recursive symbolic links to quote */
  144. static TREE *execT;            /* execute command list */
  145.  
  146. /*************************
  147.  ***    E X T E R N    ***
  148.  *************************/
  149.  
  150. #ifdef    lint
  151. static char _argbreak;
  152. #else
  153. extern char _argbreak;            /* break character from nxtarg */
  154. #endif
  155.  
  156. extern TREELIST *listTL;        /* list of trees for scanning */
  157. extern TREE *listT;            /* final list of files in collection */
  158. extern TREE *refuseT;            /* files refused by client */
  159.  
  160. extern char *collname;            /* collection name */
  161. extern char *basedir;            /* base directory name */
  162. extern char *prefix;            /* collection pathname prefix */
  163. extern long lasttime;            /* time of last upgrade */
  164. extern long scantime;            /* time of this scan */
  165. extern int trace;            /* trace directories */
  166. extern int newonly;            /* new files only */
  167.  
  168. extern long time();
  169.  
  170. /*************************************************
  171.  ***   STATIC   R O U T I N E S    ***
  172.  *************************************************/
  173.  
  174. static makescan();
  175. static getscan();
  176. static doscan();
  177. static readlistfile();
  178. static expTinsert();
  179. static listone();
  180. static listentry();
  181. static listname();
  182. static listdir();
  183. static omitanyone();
  184. static anyglob();
  185. static int getscanfile();
  186. static chkscanfile();
  187. static makescanfile();
  188. static recordone();
  189. static recordexec();
  190.  
  191. /*************************************************
  192.  ***    L I S T   S C A N   R O U T I N E S    ***
  193.  *************************************************/
  194.  
  195. static
  196. passdelim (ptr,delim)        /* skip over delimiter */
  197. char **ptr,delim;
  198. {
  199.     *ptr = skipover (*ptr, " \t");
  200.     if (_argbreak != delim && **ptr == delim) {
  201.         (*ptr)++;
  202.         *ptr = skipover (*ptr, " \t");
  203.     }
  204. }
  205.  
  206. static
  207. char *parserelease(tlp,relname,args)
  208. TREELIST **tlp;
  209. char *relname,*args;
  210. {
  211.     register TREELIST *tl;
  212.     register char *arg;
  213.     register OPTION option;
  214.     int opno;
  215.     char *nextrel;
  216.  
  217.     tl = (TREELIST *) malloc (sizeof(TREELIST));
  218.     if ((*tlp = tl) == NULL)
  219.         goaway ("Couldn't allocate TREELIST");
  220.     tl->TLnext = NULL;
  221.     tl->TLname = salloc (relname);
  222.     tl->TLprefix = NULL;
  223.     tl->TLlist = NULL;
  224.     tl->TLscan = NULL;
  225.     tl->TLhost = NULL;
  226.     nextrel = NULL;
  227.     args = skipover (args," \t");
  228.     while (*(arg=nxtarg(&args," \t="))) {
  229.         for (opno = 0; options[opno] != NULL; opno++)
  230.             if (strcmp (arg,options[opno]) == 0)
  231.                 break;
  232.         if (options[opno] == NULL)
  233.             goaway ("Invalid release option %s for release %s",
  234.                 arg,relname);
  235.         option = (OPTION) opno;
  236.         switch (option) {
  237.         case ONEXT:
  238.             passdelim (&args,'=');
  239.             arg = nxtarg (&args," \t");
  240.             nextrel = salloc (arg);
  241.             break;
  242.         case OPREFIX:
  243.             passdelim (&args,'=');
  244.             arg = nxtarg (&args," \t");
  245.             tl->TLprefix = salloc (arg);
  246.             break;
  247.         case OLIST:
  248.             passdelim (&args,'=');
  249.             arg = nxtarg (&args," \t");
  250.             tl->TLlist = salloc (arg);
  251.             break;
  252.         case OSCAN:
  253.             passdelim (&args,'=');
  254.             arg = nxtarg (&args," \t");
  255.             tl->TLscan = salloc (arg);
  256.             break;
  257.         case OHOST:
  258.             passdelim (&args,'=');
  259.             arg = nxtarg (&args," \t");
  260.             tl->TLhost = salloc (arg);
  261.             break;
  262.         }
  263.     }
  264.     return (nextrel);
  265. }
  266.  
  267. getrelease (release)
  268. char *release;
  269. {
  270.     TREELIST *tl;
  271.     char buf[STRINGLENGTH];
  272.     char *p,*q;
  273.     int rewound;
  274.     FILE *f;
  275.  
  276.     if (release == NULL)
  277.         release = salloc (DEFRELEASE);
  278.     listTL = NULL;
  279.  
  280.     (void) sprintf (buf,FILERELEASES,collname);
  281.     f = fopen (buf,"r");
  282.     if (f != NULL) {
  283.         rewound = TRUE;
  284.         for (;;) {
  285.             p = fgets (buf,STRINGLENGTH,f);
  286.             if (p == NULL) {
  287.                 if (rewound)
  288.                     break;
  289.                 rewind (f);
  290.                 rewound = TRUE;
  291.                 continue;
  292.             }
  293.             q = index (p,'\n');
  294.             if (q)  *q = 0;
  295.             if (index ("#;:",*p))  continue;
  296.             q = nxtarg (&p," \t");
  297.             if (strcmp (q,release) != 0)
  298.                 continue;
  299.             release = parserelease (&tl,release,p);
  300.             if (tl->TLprefix == NULL)
  301.                 tl->TLprefix = prefix;
  302.             else if (chdir (tl->TLprefix) < 0)
  303.                 return (FALSE);
  304.             else
  305.                 (void) chdir (basedir);
  306.             tl->TLnext = listTL;
  307.             listTL = tl;
  308.             if (release == NULL)
  309.                 break;
  310.             rewound = FALSE;
  311.         }
  312.         (void) fclose (f);
  313.     }
  314.     if (release == NULL)
  315.         return (TRUE);
  316.     if (strcmp (release,DEFRELEASE) != 0)
  317.         return (FALSE);
  318.     (void) parserelease (&tl,release,"");
  319.     tl->TLprefix = prefix;
  320.     tl->TLnext = listTL;
  321.     listTL = tl;
  322.     return (TRUE);
  323. }
  324.  
  325. makescanlists ()
  326. {
  327.     TREELIST *tl;
  328.     char buf[STRINGLENGTH];
  329.     char *p,*q;
  330.     FILE *f;
  331.     char *saveprefix = prefix;
  332.     int count = 0;
  333.  
  334.     (void) sprintf (buf,FILERELEASES,collname);
  335.     f = fopen (buf,"r");
  336.     if (f != NULL) {
  337.         while (p = fgets (buf,STRINGLENGTH,f)) {
  338.             q = index (p,'\n');
  339.             if (q)  *q = 0;
  340.             if (index ("#;:",*p))  continue;
  341.             q = nxtarg (&p," \t");
  342.             (void) parserelease (&tl,q,p);
  343.             if ((prefix = tl->TLprefix) == NULL)
  344.                 prefix = saveprefix;
  345.             if (prefix != NULL) {
  346.                 if (chdir (prefix) < 0)
  347.                     goaway ("Can't chdir to %s",prefix);
  348.                 (void) chdir (basedir);
  349.             }
  350.             makescan (tl->TLlist,tl->TLscan);
  351.             free ((char *)tl);
  352.             count++;
  353.         }
  354.         (void) fclose (f);
  355.     }
  356.     if (count == 0)
  357.         makescan ((char *)NULL,(char *)NULL);
  358. }
  359.  
  360. static
  361. scanone (t)
  362. register TREE *t;
  363. {
  364.     register TREE *newt;
  365.  
  366.     if (newonly && (t->Tflags&FNEW) == 0)
  367.         return (SCMOK);
  368.     newt = Tinsert (&listT,t->Tname,FALSE);
  369.     if (newt == NULL)
  370.         return (SCMOK);
  371.     newt->Tmode = t->Tmode;
  372.     newt->Tflags = t->Tflags;
  373.     newt->Tmtime = t->Tmtime;
  374.     return (SCMOK);
  375. }
  376.  
  377. getscanlists ()
  378. {
  379.     TREELIST *tl,*stl;
  380.  
  381.     stl = listTL;
  382.     listTL = NULL;
  383.     while ((tl = stl) != NULL) {
  384.         prefix = tl->TLprefix;
  385.         getscan (tl->TLlist,tl->TLscan);
  386.         tl->TLtree = listT;
  387.         stl = tl->TLnext;
  388.         tl->TLnext = listTL;
  389.         listTL = tl;
  390.     }
  391.     listT = NULL;
  392.     for (tl = listTL; tl != NULL; tl = tl->TLnext)
  393.         (void) Tprocess (tl->TLtree,scanone);
  394. }
  395.  
  396. static
  397. makescan (listfile,scanfile)
  398. char *listfile,*scanfile;
  399. {
  400.     listT = NULL;
  401.     chkscanfile (scanfile);        /* can we can write a scan file? */
  402.     doscan (listfile);        /* read list file and scan disk */
  403.     makescanfile (scanfile);    /* record names in scan file */
  404.     Tfree (&listT);            /* free file list tree */
  405. }
  406.  
  407. static
  408. getscan (listfile,scanfile)
  409. char *listfile,*scanfile;
  410. {
  411.     listT = NULL;
  412.     if (!getscanfile(scanfile)) {    /* check for pre-scanned file list */
  413.         scantime = time ((long *)NULL);
  414.         doscan (listfile);    /* read list file and scan disk */
  415.     }
  416. }
  417.  
  418. static
  419. doscan (listfile)
  420.     char *listfile;
  421. {
  422.     char buf[STRINGLENGTH];
  423.     int listone ();
  424.  
  425.     upgT = NULL;
  426.     flagsT = NULL;
  427.     omitT = NULL;
  428.     omanyT = NULL;
  429.     execT = NULL;
  430.     symT = NULL;
  431.     rsymT = NULL;
  432.     if (listfile == NULL)
  433.         listfile = FILELISTDEF;
  434.     (void) sprintf (buf,FILELIST,collname,listfile);
  435.     readlistfile (buf);        /* get contents of list file */
  436.     (void) Tprocess (upgT,listone); /* build list of files specified */
  437.     cdprefix ((char *)NULL);
  438.     Tfree (&upgT);
  439.     Tfree (&flagsT);
  440.     Tfree (&omitT);
  441.     Tfree (&omanyT);
  442.     Tfree (&execT);
  443.     Tfree (&symT);
  444.     Tfree (&rsymT);
  445. }
  446.  
  447. static
  448. readlistfile (fname)
  449. char *fname;
  450. {
  451.     char buf[STRINGLENGTH],*p;
  452.     register char *q,*r;
  453.     register FILE *f;
  454.     register int ltn,n,i,flags;
  455.     register TREE **t;
  456.     register LISTTYPE lt;
  457.     char *speclist[SPECNUMBER];
  458.  
  459.     f = fopen (fname,"r");
  460.     if (f == NULL)  goaway ("Can't read list file %s",fname);
  461.     cdprefix (prefix);
  462.     while (p = fgets (buf,STRINGLENGTH,f)) {
  463.         if (q = index (p,'\n'))  *q = '\0';
  464.         if (index ("#;:",*p))  continue;
  465.         q = nxtarg (&p," \t");
  466.         if (*q == '\0') continue;
  467.         for (ltn = 0; ltname[ltn] && strcmp(q,ltname[ltn]) != 0; ltn++);
  468.         if (ltname[ltn] == NULL)
  469.             goaway ("Invalid list file keyword %s",q);
  470.         lt = (LISTTYPE) ltn;
  471.         flags = 0;
  472.         switch (lt) {
  473.         case LUPGRADE:
  474.             t = &upgT;
  475.             break;
  476.         case LBACKUP:
  477.             t = &flagsT;
  478.             flags = FBACKUP;
  479.             break;
  480.         case LNOACCT:
  481.             t = &flagsT;
  482.             flags = FNOACCT;
  483.             break;
  484.         case LSYMLINK:
  485.             t = &symT;
  486.             break;
  487.         case LRSYMLINK:
  488.             t = &rsymT;
  489.             break;
  490.         case LOMIT:
  491.             t = &omitT;
  492.             break;
  493.         case LOMITANY:
  494.             t = &omanyT;
  495.             break;
  496.         case LALWAYS:
  497.             t = &upgT;
  498.             flags = FALWAYS;
  499.             break;
  500.         case LINCLUDE:
  501.             while (*(q=nxtarg(&p," \t"))) {
  502.                 cdprefix ((char *)NULL);
  503.                 n = expand (q,speclist,SPECNUMBER);
  504.                 for (i = 0; i < n && i < SPECNUMBER; i++) {
  505.                     readlistfile (speclist[i]);
  506.                     cdprefix ((char *)NULL);
  507.                     free (speclist[i]);
  508.                 }
  509.                 cdprefix (prefix);
  510.             }
  511.             continue;
  512.         case LEXECUTE:
  513.             r = p = q = skipover (p," \t");
  514.             do {
  515.                 q = p = skipto (p," \t(");
  516.                 p = skipover (p," \t");
  517.             } while (*p != '(' && *p != '\0');
  518.             if (*p++ == '(') {
  519.                 *q = '\0';
  520.                 do {
  521.                     q = nxtarg (&p," \t)");
  522.                     if (*q == 0)
  523.                         _argbreak = ')';
  524.                     else
  525.                         expTinsert (q,&execT,0,r);
  526.                 } while (_argbreak != ')');
  527.                 continue;
  528.             }
  529.             /* fall through */
  530.         default:
  531.             goaway ("Error in handling list file keyword %d",ltn);
  532.         }
  533.         while (*(q=nxtarg(&p," \t"))) {
  534.             if (lt == LOMITANY)
  535.                 (void) Tinsert (t,q,FALSE);
  536.             else
  537.                 expTinsert (q,t,flags,(char *)NULL);
  538.         }
  539.     }
  540.     (void) fclose (f);
  541. }
  542.  
  543. static
  544. expTinsert (p,t,flags,exec)
  545. char *p;
  546. TREE **t;
  547. int flags;
  548. char *exec;
  549. {
  550.     register int n, i;
  551.     register TREE *newt;
  552.     char *speclist[SPECNUMBER];
  553.     char buf[STRINGLENGTH];
  554.  
  555.     n = expand (p,speclist,SPECNUMBER);
  556.     for (i = 0; i < n && i < SPECNUMBER; i++) {
  557.         newt = Tinsert (t,speclist[i],TRUE);
  558.         newt->Tflags |= flags;
  559.         if (exec) {
  560.             (void) sprintf (buf,exec,speclist[i]);
  561.             (void) Tinsert (&newt->Texec,buf,FALSE);
  562.         }
  563.         free (speclist[i]);
  564.     }
  565. }
  566.  
  567. static
  568. listone (t)        /* expand and add one name from upgrade list */
  569. TREE *t;
  570. {
  571.     listentry(t->Tname,t->Tname,(char *)NULL,(t->Tflags&FALWAYS) != 0);
  572.     return (SCMOK);
  573. }
  574.  
  575. static
  576. listentry(name,fullname,updir,always)
  577. register char *name, *fullname, *updir;
  578. int always;
  579. {
  580.     struct stat statbuf;
  581.     int link = 0;
  582.     int omitanyone ();
  583.  
  584.     if (Tlookup (refuseT,fullname))  return;
  585.     if (!always) {
  586.         if (Tsearch (omitT,fullname))  return;
  587.         if (Tprocess (omanyT,omitanyone,fullname) != SCMOK)
  588.             return;
  589.     }
  590.     if (lstat(name,&statbuf) < 0)
  591.         return;
  592.     if ((statbuf.st_mode&S_IFMT) == S_IFLNK) {
  593.         if (Tsearch (symT,fullname)) {
  594.             listname (fullname,&statbuf);
  595.             return;
  596.         }
  597.         if (Tlookup (rsymT,fullname)) {
  598.             listname (fullname,&statbuf);
  599.             return;
  600.         }
  601.         if (updir) link++;
  602.         if (stat(name,&statbuf) < 0) return;
  603.     }
  604.     if ((statbuf.st_mode&S_IFMT) == S_IFDIR) {
  605.         if (access(name,R_OK|X_OK) < 0) return;
  606.         if (chdir(name) < 0) return;
  607.         listname (fullname,&statbuf);
  608.         if (trace) {
  609.             printf ("Scanning directory %s\n",fullname);
  610.             (void) fflush (stdout);
  611.         }
  612.         listdir (fullname,always);
  613.         if (updir == 0 || link) {
  614.             (void) chdir (basedir);
  615.             if (prefix) (void) chdir (prefix);
  616.             if (updir && *updir) (void) chdir (updir);
  617.         } else
  618.             (void) chdir ("..");
  619.         return;
  620.     }
  621.     if (access(name,R_OK) < 0) return;
  622.     listname (fullname,&statbuf);
  623. }
  624.  
  625. static
  626. listname (name,st)
  627. register char *name;
  628. register struct stat *st;
  629. {
  630.     register TREE *t,*ts;
  631.     register int new;
  632.     register TREELIST *tl;
  633.  
  634.     new = st->st_ctime > lasttime;
  635.     if (newonly && !new) {
  636.         for (tl = listTL; tl != NULL; tl = tl->TLnext)
  637.             if (ts = Tsearch (tl->TLtree,name))
  638.                 ts->Tflags &= ~FNEW;
  639.         return;
  640.     }
  641.     t = Tinsert (&listT,name,FALSE);
  642.     if (t == NULL)  return;
  643.     t->Tmode = st->st_mode;
  644.     t->Tctime = st->st_ctime;
  645.     t->Tmtime = st->st_mtime;
  646.     if (new)  t->Tflags |= FNEW;
  647.     if (ts = Tsearch (flagsT,name))
  648.         t->Tflags |= ts->Tflags;
  649.     if (ts = Tsearch (execT,name)) {
  650.         t->Texec = ts->Texec;
  651.         ts->Texec = NULL;
  652.     }
  653. }
  654.  
  655. static
  656. listdir (name,always)        /* expand directory */
  657. char *name;
  658. int always;
  659. {
  660.     struct direct *dentry;
  661.     register DIR *dirp;
  662.     char ename[STRINGLENGTH],newname[STRINGLENGTH],filename[STRINGLENGTH];
  663.     register char *p,*newp;
  664.     register int i;
  665.  
  666.     dirp = opendir (".");
  667.     if (dirp == 0) return;    /* unreadable: probably protected */
  668.  
  669.     p = name;        /* punt leading ./ and trailing / */
  670.     newp = newname;
  671.     if (p[0] == '.' && p[1] == '/') {
  672.         p += 2;
  673.         while (*p == '/') p++;
  674.     }
  675.     while (*newp++ = *p++) ;    /* copy string */
  676.     --newp;                /* trailing null */
  677.     while (newp > newname && newp[-1] == '/') --newp; /* trailing / */
  678.     *newp = 0;
  679.     if (strcmp (newname,".") == 0) newname[0] = 0;    /* "." ==> "" */
  680.  
  681.     while (dentry=readdir(dirp)) {
  682.         if (dentry->d_ino == 0) continue;
  683.         if (strcmp(dentry->d_name,".") == 0) continue;
  684.         if (strcmp(dentry->d_name,"..") == 0) continue;
  685.         for (i=0; i<=MAXNAMLEN && dentry->d_name[i]; i++)
  686.             ename[i] = dentry->d_name[i];
  687.         ename[i] = 0;
  688.         if (*newname)
  689.             (void) sprintf (filename,"%s/%s",newname,ename);
  690.         else
  691.             (void) strcpy (filename,ename);
  692.         listentry(ename,filename,newname,always);
  693.     }
  694.     closedir (dirp);
  695. }
  696.  
  697. static
  698. omitanyone (t,filename)
  699. TREE *t;
  700. char **filename;
  701. {
  702.     if (anyglob (t->Tname,*filename))
  703.         return (SCMERR);
  704.     return (SCMOK);
  705. }
  706.  
  707. static
  708. anyglob (pattern,match)
  709. char *pattern,*match;
  710. {
  711.     register char *p,*m;
  712.     register char *pb,*pe;
  713.  
  714.     p = pattern; 
  715.     m = match;
  716.     while (*m && *p == *m ) { 
  717.         p++; 
  718.         m++; 
  719.     }
  720.     if (*p == '\0' && *m == '\0')
  721.         return (TRUE);
  722.     switch (*p++) {
  723.     case '*':
  724.         for (;;) {
  725.             if (*p == '\0')
  726.                 return (TRUE);
  727.             if (*m == '\0')
  728.                 return (*p == '\0');
  729.             if (anyglob (p,++m))
  730.                 return (TRUE);
  731.         }
  732.     case '?':
  733.         return (anyglob (p,++m));
  734.     case '[':
  735.         pb = p;
  736.         while (*(++p) != ']')
  737.             if (*p == '\0')
  738.                 return (FALSE);
  739.         pe = p;
  740.         for (p = pb + 1; p != pe; p++) {
  741.             switch (*p) {
  742.             case '-':
  743.                 if (p == pb && *m == '-') {
  744.                     p = pe + 1;
  745.                     return (anyglob (p,++m));
  746.                 }
  747.                 if (p == pb)
  748.                     continue;
  749.                 if ((p + 1) == pe)
  750.                     return (FALSE);
  751.                 if (*m > *(p - 1) &&
  752.                     *m <= *(p + 1)) {
  753.                     p = pe + 1;
  754.                     return (anyglob (p,++m));
  755.                 }
  756.                 continue;
  757.             default:
  758.                 if (*m == *p) {
  759.                     p = pe + 1;
  760.                     return (anyglob (p,++m));
  761.                 }
  762.             }
  763.         }
  764.         return (FALSE);
  765.     default:
  766.         return (FALSE);
  767.     }
  768. }
  769.  
  770. /*****************************************
  771.  ***    R E A D   S C A N   F I L E    ***
  772.  *****************************************/
  773.  
  774. static
  775. int getscanfile (scanfile)
  776. char *scanfile;
  777. {
  778.     char buf[STRINGLENGTH];
  779.     struct stat sbuf;
  780.     register FILE *f;
  781.     TREE ts;
  782.     register char *p,*q;
  783.     register TREE *tmp, *t = NULL;
  784.     register notwanted;
  785.     register TREELIST *tl;
  786.  
  787.     if (scanfile == NULL)
  788.         scanfile = FILESCANDEF;
  789.     (void) sprintf (buf,FILESCAN,collname,scanfile);
  790.     if (stat(buf,&sbuf) < 0)
  791.         return (FALSE);
  792.     if ((f = fopen (buf,"r")) == NULL)
  793.         return (FALSE);
  794.     if ((p = fgets (buf,STRINGLENGTH,f)) == NULL) {
  795.         (void) fclose (f);
  796.         return (FALSE);
  797.     }
  798.     if (q = index (p,'\n'))  *q = '\0';
  799.     if (*p++ != 'V') {
  800.         (void) fclose (f);
  801.         return (FALSE);
  802.     }
  803.     if (atoi (p) != SCANVERSION) {
  804.         (void) fclose (f);
  805.         return (FALSE);
  806.     }
  807.     scantime = sbuf.st_mtime;    /* upgrade time is time of supscan,
  808.                      * i.e. time of creation of scanfile */
  809.     if (newonly && scantime == lasttime) {
  810.         (void) fclose (f);
  811.         return (TRUE);
  812.     }
  813.     notwanted = FALSE;
  814.     while (p = fgets (buf,STRINGLENGTH,f)) {
  815.         q = index (p,'\n');
  816.         if (q)  *q = 0;
  817.         ts.Tflags = 0;
  818.         if (*p == 'X') {
  819.             if (notwanted)  continue;
  820.             if (t == NULL)
  821.                 goaway ("scanfile format inconsistant");
  822.             (void) Tinsert (&t->Texec,++p,FALSE);
  823.             continue;
  824.         }
  825.         notwanted = FALSE;
  826.         if (*p == 'B') {
  827.             p++;
  828.             ts.Tflags |= FBACKUP;
  829.         }
  830.         if (*p == 'N') {
  831.             p++;
  832.             ts.Tflags |= FNOACCT;
  833.         }
  834.         if ((q = index (p,' ')) == NULL)
  835.             goaway ("scanfile format inconsistant");
  836.         *q++ = '\0';
  837.         ts.Tmode = atoo (p);
  838.         p = q;
  839.         if ((q = index (p,' ')) == NULL)
  840.             goaway ("scanfile format inconsistant");
  841.         *q++ = '\0';
  842.         ts.Tctime = atoi (p);
  843.         p = q;
  844.         if ((q = index (p,' ')) == NULL)
  845.             goaway ("scanfile format inconsistant");
  846.         *q++ = 0;
  847.         ts.Tmtime = atoi (p);
  848.         if (ts.Tctime > lasttime)
  849.             ts.Tflags |= FNEW;
  850.         else if (newonly) {
  851.             for (tl = listTL; tl != NULL; tl = tl->TLnext)
  852.                 if (tmp = Tsearch (tl->TLtree,q))
  853.                     tmp->Tflags &= ~FNEW;
  854.             notwanted = TRUE;
  855.             continue;
  856.         }
  857.         if (Tlookup (refuseT,q)) {
  858.             notwanted = TRUE;
  859.             continue;
  860.         }
  861.         t = Tinsert (&listT,q,TRUE);
  862.         t->Tmode = ts.Tmode;
  863.         t->Tflags = ts.Tflags;
  864.         t->Tctime = ts.Tctime;
  865.         t->Tmtime = ts.Tmtime;
  866.     }
  867.     (void) fclose (f);
  868.     return (TRUE);
  869. }
  870.  
  871. /*******************************************
  872.  ***    W R I T E   S C A N   F I L E    ***
  873.  *******************************************/
  874.  
  875. static chkscanfile (scanfile)
  876. char *scanfile;
  877. {
  878.     char tname[STRINGLENGTH], fname[STRINGLENGTH];
  879.     FILE *f;
  880.  
  881.     if (scanfile == NULL)
  882.         scanfile = FILESCANDEF;
  883.     (void) sprintf (fname,FILESCAN,collname,scanfile);
  884.     (void) sprintf (tname,"%s.temp",fname);
  885.     if (NULL == (f = fopen (tname, "w")))
  886.         goaway ("Can't test scan file temp %s for %s",tname,collname);
  887.     else {
  888.         (void) unlink (tname);
  889.         (void) fclose (f);
  890.     }
  891. }
  892.  
  893. static makescanfile (scanfile)
  894. char *scanfile;
  895. {
  896.     char tname[STRINGLENGTH],fname[STRINGLENGTH];
  897. #ifdef _ABI_SOURCE
  898.     struct utimbuf tbuf;
  899. #else
  900.     struct timeval tbuf[2];
  901. #endif
  902.     FILE *scanF;            /* output file for scanned file list */
  903.     int recordone ();
  904.  
  905.     if (scanfile == NULL)
  906.         scanfile = FILESCANDEF;
  907.     (void) sprintf (fname,FILESCAN,collname,scanfile);
  908.     (void) sprintf (tname,"%s.temp",fname);
  909.     scanF = fopen (tname,"w");
  910.     if (scanF == NULL)
  911.         goaway ("Can't write scan file temp %s for %s",tname,collname);
  912.     fprintf (scanF,"V%d\n",SCANVERSION);
  913.     (void) Tprocess (listT,recordone,scanF);
  914.     (void) fclose (scanF);
  915.     if (rename (tname,fname) < 0)
  916.         goaway ("Can't change %s to %s",tname,fname);
  917.     (void) unlink (tname);
  918. #ifdef _ABI_SOURCE
  919.     tbuf.actime = time((time_t *)NULL);
  920.     tbuf.modtime = scantime;
  921.     (void) utime (fname,&tbuf);
  922. #else
  923.     tbuf[0].tv_sec = time((long *)NULL);  tbuf[0].tv_usec = 0;
  924.     tbuf[1].tv_sec = scantime;  tbuf[1].tv_usec = 0;
  925.     (void) utimes (fname,tbuf);
  926. #endif
  927. }
  928.  
  929. static
  930. recordone (t,scanF)
  931. TREE *t;
  932. FILE **scanF;
  933. {
  934.     int recordexec ();
  935.  
  936.     if (t->Tflags&FBACKUP)  fprintf (*scanF,"B");
  937.     if (t->Tflags&FNOACCT)  fprintf (*scanF,"N");
  938.     fprintf (*scanF,"%o %d %d %s\n",
  939.         t->Tmode,t->Tctime,t->Tmtime,t->Tname);
  940.     (void) Tprocess (t->Texec,recordexec,*scanF);
  941.     return (SCMOK);
  942. }
  943.  
  944. static
  945. recordexec (t,scanF)
  946. TREE *t;
  947. FILE **scanF;
  948. {
  949.     fprintf(*scanF,"X%s\n",t->Tname);
  950.     return (SCMOK);
  951. }
  952.  
  953. cdprefix (prefix)
  954. char *prefix;
  955. {
  956.     static char *curprefix = NULL;
  957.  
  958.     if (curprefix == NULL) {
  959.         if (prefix == NULL)
  960.             return;
  961.         (void) chdir (prefix);
  962.         curprefix = prefix;
  963.         return;
  964.     }
  965.     if (prefix == NULL) {
  966.         (void) chdir (basedir);
  967.         curprefix = NULL;
  968.         return;
  969.     }
  970.     if (prefix == curprefix)
  971.         return;
  972.     if (strcmp (prefix, curprefix) == 0) {
  973.         curprefix = prefix;
  974.         return;
  975.     }
  976.     (void) chdir (basedir);
  977.     (void) chdir (prefix);
  978.     curprefix = prefix;
  979. }
  980.